
#include "PLCP_sw_timer.h"


// When timer counter >= interval, the timeout flag will be set.
// If the cyclic flag is true, the counter will keep running.

static U8 add_overflow_check(U32 a, U32 b)
{
	U32 sum = a + b;
	if(sum < a || sum < b){
		return 1;
	}
	else{
		return 0;
	}
}

static U8 sw_timer_timeout_cyclic_handler(SW_TIMER_STRUCT* sw_timer)
{
    sw_timer->state.timeout = 1;
    if(sw_timer->timeout_callback){
        sw_timer->timeout_callback(sw_timer, sw_timer->param);
    }
    if(!sw_timer->state.cyclic){
        sw_timer->counter = 0;
        sw_timer->state.enable = 0;
        return 0;
    }
	return 1;
}

static U8 sw_timer_check(SW_TIMER_STRUCT* sw_timer)
{
	if((!sw_timer->state.enable)||(sw_timer->interval == 0)
		||(sw_timer->counter >= sw_timer->interval)){
		return 0;
	}
	else{
		return 1;
	}
}

void sw_timer_tick_handler(SW_TIMER_STRUCT* sw_timer, U32 ticks)
{
	U8 ticks_overflow;

	if((sw_timer == 0)||(ticks == 0)){
		return;
	}
	if(!sw_timer_check(sw_timer)){
		return;
	}

	//ticks + sw_timer->counter < sw_timer->interval
	if(ticks  < sw_timer->interval - sw_timer->counter){
		sw_timer->counter += ticks;
		return;
	}

	//ticks + sw_timer->counter >= sw_timer->interval
	ticks_overflow = add_overflow_check(ticks, sw_timer->counter);
	ticks += sw_timer->counter;
	while((ticks_overflow)||(ticks >= sw_timer->interval)){
		if(!sw_timer_check(sw_timer)){
			break;
		}	
		if(ticks >= sw_timer->interval){
			ticks -= sw_timer->interval;
			if(!sw_timer_timeout_cyclic_handler(sw_timer)){
				break;
			}
			continue;
		}
		if(ticks_overflow){
			//in here: ticks < sw_timer->interval
			//so (0xffffffff + 1 - sw_timer->interval + ticks) will NOT overflow
			//ticks = 0xffffffff + 1 - sw_timer->interval + ticks;
			sw_timer->counter = 0xffffffff - sw_timer->interval + 1;
			ticks += sw_timer->counter;
			ticks_overflow = 0;
			if(!sw_timer_timeout_cyclic_handler(sw_timer)){
				break;
			}
		}
	}
	if(sw_timer->state.cyclic){
		sw_timer->counter = ticks;
	}
}


